package szte.objectorgy.collections;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.NoSuchElementException;

/**
 * Array list implementation of the list data structure.
 * 
 * @author Csilla-Andrea KAPUSI
 * @param <T>
 *            The type of the elements stored in this collection.
 */
public class Vector<T extends Comparable<T>> implements List<T> {

	protected int count;
	protected int size;
	protected T[] elements;

	@SuppressWarnings("unchecked")
	public Vector(Class<T> type) {
		super();
		count = 0;
		size = 5;
		
		elements = (T[]) Array.newInstance(type, size);
	}

	@SuppressWarnings("unchecked")
	@Override
	public void add(T element) {
		if (count < size) {
			elements[count++] = element;
		} else {
			T[] copy = elements;
			size += size / 2;
			elements = (T[]) Array.newInstance(element.getClass(), size);
			System.arraycopy(copy, 0, elements, 0, count);
			elements[count++] = element;
		}
	}

	@Override
	public void addAll(Collection<T> collection) {
		Iterator<T> it = collection.getIterator();
		while (it.hasNext()) {
			add(it.next());
		}
	}

	@Override
	public void clear() {
		count = 0;
	}

	@Override
	public boolean contains(T element) {
		return indexOf(element) != -1;
	}

	@Override
	public boolean isEmpty() {
		return count == 0;
	}

	@Override
	public Iterator<T> getIterator() {
		return new VectorIterator();
	}

	@Override
	public void remove(T element) {
		int index = indexOf(element);
		if (index == -1) {
			return;
		}
		count--;
		int n = count - index;
		if (n > 0) {
			System.arraycopy(elements, index + 1, elements, index, n);
		}
		elements[count] = null;
	}

	@Override
	public void removeAll(Collection<T> collection) {
		Iterator<T> it = collection.getIterator();
		while (it.hasNext()) {
			remove(it.next());
		}
	}

	@Override
	public int size() {
		return count;
	}

	@Override
	public Object[] toArray() {
		Object[] obj = new Object[count];
		System.arraycopy(elements, 0, obj, 0, count);
		return obj;
	}

	@Override
	public void add(int index, T element) {
		if (0 <= index && index <= count) {
			int n = count - index;
			if (count > 0) {
				System.arraycopy(elements, index, elements, index + 1, n);
			}
			elements[index] = element;
			count++;
		} else {
			throw new ArrayIndexOutOfBoundsException(index);
		}
	}

	@Override
	public T get(int index) {
		if (index < count) {
			return elements[index];
		}
		throw new ArrayIndexOutOfBoundsException(index);
	}

	@Override
	public int indexOf(T element) {
		for (int i = 0; i < count; i++) {
			if (element.equals(elements[i])) {
				return i;
			}
		}
		return -1;
	}

	@Override
	public void set(int index, T element) {
		if (index < count) {
			elements[index] = element;
		} else {
			throw new ArrayIndexOutOfBoundsException(index);
		}
	}

	public class VectorIterator implements Iterator<T> {
		int numLeft = size();
		int lastPosition = -1;

		@Override
		public boolean hasNext() {
			return numLeft > 0;
		}

		@Override
		public T next() {
			try {
				int index = size() - numLeft;
				T result = get(index);
				lastPosition = index;
				numLeft--;
				return result;
			} catch (IndexOutOfBoundsException e) {
				throw new NoSuchElementException();
			}
		}
	}
	
	public String toString() {
		return Arrays.toString(elements);
	}
}
